package com.hontech.libratest.conn

import com.hontech.libratest.app.AppTask
import com.hontech.libratest.except.ExecFailException
import com.hontech.libratest.utils.*
import kotlinx.coroutines.CompletableDeferred
import java.security.MessageDigest

class OtaTask (val data: ByteArray,
               val progFn: (prog: Int) -> Unit,
               val deferred: CompletableDeferred<Unit>) : Runnable {

    override fun run() {
        try {
            exec()
            deferred.complete(Unit)
        } catch (e: Exception) {
            e.printStackTrace()
            deferred.completeExceptionally(e)
        }
    }

    private fun request(req: Int, args: Array<SerialType>, timeout: Long, msg: String) {
        val frame = Device.send(Device.destAddr, req, args, timeout)
        val value = UInt8()
        frame.parse(arrayOf(value))
        if (!value.isOk()) {
            throw ExecFailException("${msg} 异常:${value.errMsg()}")
        }
    }

    private fun start() {
        request(Proto.OtaStart, arrayOf(UInt32(data.size)), 5 * 1000L, "ota start")
    }

    private fun translate() {
        var index = 0
        var id = 0
        while (index < data.size) {
            var n = data.size - index
            if (n > 32) {
                n = 32
            }
            request(Proto.OtaTranslate, arrayOf(UInt16(id), ByteView(data, index, n)),
                3 * 1000L, "ota translate")
            index += n
            id += 1
            AppTask.post { progFn(index * 100 / data.size) }
        }
    }

    private fun complete() {
        val buf = MessageDigest.getInstance("MD5").digest(data)
        request(Proto.OtaComplete, arrayOf(ByteView(buf)), 5 * 1000L, "ota complete")
    }

    private fun exec() {
        start()
        translate()
        complete()
    }
}
